package studio.raptor.databus.graph.repository;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementSetter;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
import studio.raptor.databus.graph.domain.Event;

/**
 * 操作图数据库的dao实现
 *
 * @author jack
 * @since 1.0
 */
@Repository
public class EventRepository {


  static String CREATE_NODE = "MERGE(event:%s {code:{1}, eventId:{2},"
      + " status:{3}, prodId:{4},"
      + " orderTypeId:{5}, acctId:{6}, partyId:{7},"
      + " offerId:{8},offerProdId:{9}})";

  static String CREATE_RELATION = "MATCH(a: %s {eventId:{1}}) ,(b:%s) WHERE b.eventId in {2}  "
      + "CREATE UNIQUE (b)-[:DEPEND]->(a)";

  static String UPDATE_STATUS = "MATCH(a: %s {eventId:{1},code:{2}}) SET a.status = {3}";

  static String CREATE_RELATION_WITH_ROOT = "MERGE(root: %s {eventId:0,name:'root'}) "
      + " MERGE (event:%s {code:{1}, eventId:{2}, status:{3}, prodId:{4}, "
      + "  orderTypeId: {5}, acctId:{6}, partyId:{7},offerId:{8},offerProdId:{9}}) "
      + " MERGE (root)-[:DEPEND]->(event)";

  static String DELETE_NODE = "MATCH(a: %s {eventId:{1},code:{2}}) DETACH DELETE a";

  static String FIND_ALL = "MATCH (n) "
      + "RETURN n.code as code,n.status as status, "
      + "n.orderTypeId as orderTypeId, n.acctId as acctId, n.partyId as partyId, "
      + "n.offerId as offerId, n.offer2Prod as offerProdId, n.prodId as prodId, n.eventId as eventId ORDER BY n.id";

  static String CREATE_RELATIONS_WITH_ROOT = "MATCH(root: %s {eventId:0,name:'root'}) "
      + "MATCH(event:%s) WHERE event.eventId in {1}  "
      + "MERGE (root)-[:DEPEND]->(event)";

  @Autowired
  JdbcTemplate template;


  public void create(final String name,final int age) {
    String sql ="create(n:Person {name:{1},age:{2}})";
    template.update(sql, new PreparedStatementSetter() {
      @Override
      public void setValues(PreparedStatement ps) throws SQLException {
        ps.setString(1, name);
        ps.setInt(2, age);
      }
    });
  }

  /**
   * 保存事件节点，并与root节点建立关系
   */
  public int createRelationshipWithRoot(final Event event) {
    String sql = String.format(CREATE_RELATION_WITH_ROOT, event.getName(), event.getName());
    return template.update(sql,
        new PreparedStatementSetter() {

          @Override
          public void setValues(PreparedStatement ps) throws SQLException {
            ps.setString(1, event.getCode());
            ps.setString(2, event.getEventId());
            ps.setString(3, event.getStatus());

            if (null == event.getProdId()) {
              ps.setLong(4, 0);
            } else {
              ps.setLong(4, event.getProdId());
            }
            ps.setString(5, event.getOrderTypeId());
            ps.setObject(6, event.getAccountId());
            if (null == event.getPartyId()) {
              ps.setLong(7, 0);
            } else {
              ps.setLong(7, event.getPartyId());
            }
            ps.setObject(8, event.getOffer());
            ps.setObject(9, event.getOfferProdId());

          }
        });
  }

  /**
   * 保存事件到图数据库中，建立事件节点
   *
   * @param event 事件对象，包含事件的id，状态，接口等信息
   */
  public int insertEvent(final Event event) {
    String sql = String.format(CREATE_NODE, event.getName());
    return template.update(sql,
        new PreparedStatementSetter() {

          @Override
          public void setValues(PreparedStatement ps) throws SQLException {
            ps.setString(1, event.getCode());
            ps.setString(2, event.getEventId());
            ps.setString(3, event.getStatus());
            if (null == event.getProdId()) {
              ps.setLong(4, 0);
            } else {
              ps.setLong(4, event.getProdId());
            }
            ps.setString(5, event.getOrderTypeId());
            ps.setObject(6, event.getAccountId());
            if (null == event.getPartyId()) {
              ps.setLong(7, 0);
            } else {
              ps.setLong(7, event.getPartyId());
            }
            ps.setObject(8, event.getOffer());
            ps.setObject(9, event.getOfferProdId());
          }
        });
  }

  /**
   * 创建节点间的依赖关系
   *
   * @param eventId 依赖事件id
   * @param dependEventIds 被依赖的事件id集合
   * @param label 节点标签，用于区分是哪个接口，默认用接口名
   */
  public int insertAndCreateRelation(final String eventId, final Set<String> dependEventIds,
      String label) {
    String sql = String.format(CREATE_RELATION, label, label);

    return template.update(sql,
        new PreparedStatementSetter() {

          @Override
          public void setValues(PreparedStatement ps) throws SQLException {
            ps.setString(1, eventId);
            ps.setObject(2, dependEventIds);
          }
        });
  }

  /**
   * 创建节点间与root节点的依赖关系
   *
   * @param eventIds 事件id集合
   * @param code 接口编码
   * @param label 节点标签，用于区分是哪个接口，默认用接口名
   */
  public int createRelationWithRoot(final Set<String> eventIds, final String code, String label) {
    String sql = String.format(CREATE_RELATIONS_WITH_ROOT, label, label);

    return template.update(sql,
        new PreparedStatementSetter() {

          @Override
          public void setValues(PreparedStatement ps) throws SQLException {
            ps.setObject(1, eventIds);
          }
        });
  }

  /**
   * 更新图数据库事件节点状态
   *
   * @param eventId 需要更新的事件id
   * @param label 节点标签
   * @param code 接口编码
   * @param status 节点待更新的状态
   */
  public void updateEventStatusByEventId(final String eventId, String label, final String code,
      final String status) {
    String sql = String.format(UPDATE_STATUS, label);

    template.update(sql,
        new PreparedStatementSetter() {

          @Override
          public void setValues(PreparedStatement ps) throws SQLException {
            ps.setString(1, eventId);
            ps.setString(2, code);
            ps.setString(3, status);
          }
        });
  }


  /**
   * 根据事件id删除节点
   */
  public int deleteNodeByEventId(final String eventId, final String code, String label) {
    String sql = String.format(DELETE_NODE, label);
    return template.update(sql,
        new PreparedStatementSetter() {

          @Override
          public void setValues(PreparedStatement ps) throws SQLException {
            ps.setString(1, eventId);
            ps.setString(2, code);
          }
        });
  }

  /**
   * 获取所有事件节点
   */
  public List<Event> findAll() {

    return template.query(FIND_ALL, new RowMapper<Event>() {
      @Override
      public Event mapRow(ResultSet rs, int rowNum) throws SQLException {

        Event event = new Event();
        //忽略root节点
        if ("0".equals(rs.getString("eventId"))) {
          return event;
        }

        event.setCode(rs.getString("code"));
        event.setEventId(rs.getString("eventId"));
        event.setStatus(rs.getString("status"));
        event.setOrderTypeId(rs.getString("orderTypeId"));
        Long prodId = rs.getLong("prodId");
        if (prodId != null && !prodId.equals(0L)) {
          event.setProdId(rs.getLong("prodId"));
        }
        Long partyId = rs.getLong("partyId");
        if (partyId != null && !partyId.equals(0L)) {
          event.setPartyId(rs.getLong("partyId"));
        }
        Object offer = rs.getObject("offerId");
        if (null != offer) {
          List<Long> offerArray = (List<Long>) offer;
          event.setOffer(offerArray);
        }
        Object accountId = rs.getObject("acctId");
        if (null != accountId) {
          List<Long> accountArray = (List<Long>) accountId;
          event.setAccountId(accountArray);
        }
        Object offerProdId = rs.getObject("offerProdId");
        if (null != offerProdId) {
          List<Long> offerProdArray = (List<Long>) offerProdId;
          event.setOfferProdId(offerProdArray);
        }

        return event;
      }
    });
  }
}
